
#ifndef CIRCUITO_H_
#define CIRCUITO_H_
#include <list>

#include "Cable.h"


#include "Xor.h"
#include "Not.h"
#include "And.h"
#include "Or.h"
#include "Entrada.h"
#include "Salida.h"
#include "ElementoCircuital.h"
#include "Compuerta.h"
#include "ElementoExterno.h"
#include "Tabla.h"

class Circuito {
private:
	std:: list<Salida*> L_salidas;
	std:: list<Entrada*> L_entradas;
	std:: list<Compuerta*> L_compuertas;
	std:: list<ElementoExterno*> L_elementos_externos;
	int cant_entradas;
	int cant_salidas;
	Tabla tabla;
	std::string nombre;

	int nro_id;

	/*
	 * La lista de cables contiene los cables y sus respectivos puntos de quiebre
	 * Es un dato que utiliza la vista para pintar correpondientemete
	 */
	std::list<Cable*> L_cables;

public:
	Circuito(std::string nom);
	Circuito(std::list<Entrada*>* lista_entradas,std::list<Salida*>* lista_salidas ,std::list<Compuerta*>* lista_compuertas, std::list<Cable*>* pListaCables, std::list<ElementoExterno*>* lista_elementos_externos, std::string nom);
	virtual ~Circuito();

	std:: list<Salida*> get_lista_salidas();
	std:: list<Entrada*> get_lista_entradas();
	std:: list<Compuerta*> get_lista_compuertas();
	std:: list<ElementoExterno*> get_lista_elementos_externos();
	std:: list<Cable*> get_lista_cables();
	std::string get_nombre(){return nombre;}
	int get_id_maximo();

	/*
	 * Agrego un cable al circuito (lo agrega a la lista de cables)
	 */
	void agregar_cable(Cable* cable);

	/*
	 * Agrega un punto al cable que esta en la punta de la lista
	 */
	void agregar_punto(int x, int y);

	/*
	 * Selecciona los cables que estan conectados a la compuerta de posicion x, y
	 */
	void selecc_cables_conectados(int x, int y);

	/*
	 * Selecciona los cables que estan conectados al elemento externo
	 */
	void sel_cable_conect_elemexterno(ElementoCircuital* externo);

	/*
	 * Saca los cables cuya posicion inicial o final coincide con x e y
	 */
	void quitar_cables(int x, int y);

	/*
	 * Recalcula la posicion de los cables que estan moviendose por un extremo
	 */
	void recalcular_pos_cables (int posicion_x, int posicion_y);

	/*
	 * Recalcula la posicion relativa de los cables que estan moviendose por un extremo
	 */
	void recalcular_pos_rel_cables(int pos_x_inicial,int pos_y_inicial, int x, int y);


	bool circuito_listo();

	void set_id(int id){
		this->nro_id = id;
	}
	void deshacer_seleccion_cables();

	bool quitar_cable(ElementoCircuital* inicial, ElementoCircuital* final);
	void agregar_cable_entre_puntos(ElementoCircuital* inicial, ElementoCircuital* final);

	/*
	 * Saca los cables del elemento externo
	 */
	void quitar_cables_elem_ext(ElementoExterno* elemento);

	void sacar_cable(Cable* cable);

	ElementoCircuital* nueva_entrada(int x, int y, int id, std::string nom);
	ElementoCircuital* nueva_salida(int x, int y, int id, std::string nom);
	ElementoCircuital* nueva_or(int x, int y, int id, int tiempo);
	ElementoCircuital* nueva_and(int x, int y, int id, int tiempo);
	ElementoCircuital* nueva_xor(int x, int y, int id, int tiempo);
	ElementoCircuital* nueva_not(int x, int y, int id, int tiempo);
	ElementoCircuital* nueva_elemento_externo(int x, int y, int ID, std::string IP ,int port, Cliente* cliente,int cant_entrada,int cant_salida, std::string name);
	void borrar_elemento(int ID);
	std::string simular();
	std::string simular_una_vez();
	void setear_entradas(int iteracion);
	int calcular_t_transicion();
	template <class T>void borrar_de_lista(std::list<T*>* lista,int id);
	template <class T>T* buscar_en_lista(std::list<T*>* lista, int id);
	template <class T>void liberar_lista(std::list<T*>* lista);
};



//Metodos de manejo de listas Templates:

template <class T>
T* Circuito:: buscar_en_lista(std::list<T*>* lista,int id){
	typename std::list<T*>::const_iterator lit(lista->begin());
	typename std::list<T*>::const_iterator lend(lista->end());
	int encontrado=0;
	if(lista->empty())
		return NULL;
	else{
		while((!encontrado) && (lit!=lend)){
			if((*(lit))->get_id()==id)
				encontrado=1;
			else
				++lit;
		}
		if(encontrado)
			return *lit;
		else
			return NULL;
	}
}


template<class T>
void Circuito:: borrar_de_lista(std::list<T*>* lista,int id){
	typename std::list<T*>::iterator lit(lista->begin());
	typename std::list<T*>::const_iterator lend(lista->end());
	int encontrado=0;
	if(lista->empty())
		return;
	else{
		while((!encontrado) && (lit!=lend)){
			if((*(lit))->get_id()==id)
				encontrado=1;
			else
				++lit;
		}
		if(encontrado){
			delete *lit;
			lista->erase(lit);
		}
		return;
	}
}

template <class T>
void Circuito:: liberar_lista(std::list<T*>* lista){
	typename std::list<T*>::iterator lit(lista->begin());
	typename std::list<T*>::const_iterator lend(lista->end());
	if(lista->empty())
		return;
	else{
		while(lit!=lend){
			delete *lit;
				++lit;
		}
		lista->clear();
	}
}

#endif /* CIRCUITO_H_ */
